
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <iomanip>

using namespace std;

namespace ioscolor
{
    // the following are UBUNTU/LINUX ONLY terminal color codes.
    const string RESET = "\033[0m";               /* defult */
    const string BLACK = "\033[30m";              /* Black */
    const string RED = "\033[31m";                /* Red */
    const string GREEN = "\033[32m";              /* Green */
    const string YELLOW = "\033[33m";             /* Yellow */
    const string BLUE = "\033[34m";               /* Blue */
    const string MAGENTA = "\033[35m";            /* Magenta */
    const string CYAN = "\033[36m";               /* Cyan */
    const string WHITE = "\033[37m";              /* White */
    const string BOLDBLACK = "\033[1m\033[30m";   /* Bold Black */
    const string BOLDRED = "\033[1m\033[31m";     /* Bold Red */
    const string BOLDGREEN = "\033[1m\033[32m";   /* Bold Green */
    const string BOLDYELLOW = "\033[1m\033[33m";  /* Bold Yellow */
    const string BOLDBLUE = "\033[1m\033[34m";    /* Bold Blue */
    const string BOLDMAGENTA = "\033[1m\033[35m"; /* Bold Magenta */
    const string BOLDCYAN = "\033[1m\033[36m";    /* Bold Cyan */
    const string BOLDWHITE = "\033[1m\033[37m";   /* Bold White */
}

static std::string GetNow(
    const char *fmt = "%Y-%m-%d %H:%M:%S",
    int time_zone = 8)
{
    std::time_t unix_sec = std::time(nullptr);
    std::tm tm;
    static const int kHoursInDay = 24;
    static const int kMinutesInHour = 60;
    static const int kDaysFromUnixTime = 2472632;
    static const int kDaysFromYear = 153;
    static const int kMagicUnkonwnFirst = 146097;
    static const int kMagicUnkonwnSec = 1461;
    tm.tm_sec = unix_sec % kMinutesInHour;
    int i = (unix_sec / kMinutesInHour);
    tm.tm_min = i % kMinutesInHour; // nn
    i /= kMinutesInHour;
    tm.tm_hour = (i + time_zone) % kHoursInDay; // hh
    tm.tm_mday = (i + time_zone) / kHoursInDay;
    int a = tm.tm_mday + kDaysFromUnixTime;
    int b = (a * 4 + 3) / kMagicUnkonwnFirst;
    int c = (-b * kMagicUnkonwnFirst) / 4 + a;
    int d = ((c * 4 + 3) / kMagicUnkonwnSec);
    int e = -d * kMagicUnkonwnSec;
    e = e / 4 + c;
    int m = (5 * e + 2) / kDaysFromYear;
    tm.tm_mday = -(kDaysFromYear * m + 2) / 5 + e + 1;
    tm.tm_mon = (-m / 10) * 12 + m + 2;
    tm.tm_year = b * 100 + d - 6700 + (m / 10);
    stringstream ss;
    ss << std::put_time(&tm, fmt); // #include <iomanip>
    return ss.str();
}

static std::ostream logstr(cout.rdbuf()); // 设置 buff 为 标准输出的 buff

void SetLogBuf(std::streambuf *buf)
{
    logstr.rdbuf(buf);
}

void LogWrite(const string level, const string log, const string file, const int line)
{
    if (logstr.rdbuf() == cout.rdbuf() || logstr.rdbuf() == cerr.rdbuf() || logstr.rdbuf() == clog.rdbuf())
    {
        logstr
            << ioscolor::YELLOW
            << GetNow() << " "
            << ioscolor::GREEN
            << level << " "
            << ioscolor::RESET
            << log << " "
            << ioscolor::BLUE
            << file << ":" << line
            << ioscolor::RESET
            << std::endl;
    }
    else
    {
        logstr
            << GetNow() << " "
            << level << " "
            << log << " "
            << file << ":" << line
            << std::endl;
    }
}

#define LOGDEBUG(s) LogWrite("debug", s, __FILE__, __LINE__)

int main(int argc, char const *argv[])
{
    LOGDEBUG("没事儿");
    LOGDEBUG("快结束了");

    stringstream ss;
    SetLogBuf(ss.rdbuf());

    LOGDEBUG("换地方了");

    cout << "stringstream(): " << ss.str() << endl;

    ofstream ofs("log.txt", ios::app | ios::binary);
    SetLogBuf(ofs.rdbuf());
    LOGDEBUG("写文件里了");

    ofs.close();

    return 0;
}
